package com.changpei.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.changpei.common.cache.RedisUtil;
import com.changpei.common.cache.UserCache;
import com.changpei.common.cache.enums.CacheCode;
import com.changpei.common.result.Result;
import com.changpei.common.utils.JsonUtil;
import com.changpei.common.utils.PageUtil;
import com.changpei.core.feign.CommentFeign;
import com.changpei.search.dao.CommentIndexMapper;
import com.changpei.search.pojo.CommentIndex;
import com.changpei.search.service.CommentIndexService;
import com.changpei.search.utils.SearchUtil;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ScrolledPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * <p>Title: Comment</p>
 * <p>Description: Comment业务层接口实现类</p>
 * @author weibiao
 */
@Service
@Slf4j
public class CommentIndexServiceImpl implements CommentIndexService {

    @Autowired
    private CommentFeign commentFeign;

    @Autowired
    private CommentIndexMapper commentIndexMapper;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private UserCache userCache;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void importData() {
        commentIndexMapper.saveAll(JsonUtil.jsonToList(commentFeign.findAll().getData(), CommentIndex.class));
    }

    @Override
    public Page<CommentIndex> search(CommentIndex commentIndex, int pageNum, int pageSize) {
        return commentIndexMapper.search(SearchUtil.buildBasicQuery(commentIndex, pageNum, pageSize).build());
    }

    @Override
    public Result<String> save(CommentIndex commentIndex) {
        try {
            commentIndexMapper.save(commentIndex);
            return Result.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("Comment数据新增ES库失败", e.getMessage());
            return Result.failed();
        }
    }

    @Override
    public Result<String> deleteAll() {
        try {
            commentIndexMapper.deleteAll();
            return Result.ok();
        } catch (Exception e) {
            log.warn("清空Comment - ES库失败", e.getMessage());
            return Result.failed();
        }
    }

    @Override
    public Result<String> update(CommentIndex commentIndex) {
        try {
            commentIndexMapper.save(commentIndex);
            return Result.ok();
        } catch (Exception e) {
            log.warn("Comment数据更新ES库失败", e.getMessage());
            return Result.failed();
        }
    }

    @Override
    public Result<String> deleteById(Long id) {
        try {
            commentIndexMapper.deleteById(id);
            return Result.ok();
        } catch (Exception e) {
            log.warn("删除Comment - ES库失败", e.getMessage());
            return Result.failed();
        }
    }

    @Override
    public CommentIndex findById(Long id) {
        return commentIndexMapper.findById(id).get();
    }

    @Override
    public List<CommentIndex> findAll() {
        return Lists.newArrayList(commentIndexMapper.findAll());
    }

    @Override
    public Map<String, Object> findByContentId(Map<String, Object> map) {

        String token = map.get("token").toString();
        Long contentId = Long.parseLong(map.get("contentId").toString());
        int pageNum = Integer.parseInt(map.get("pageNum").toString());
        int pageSize = Integer.parseInt(map.get("pageSize").toString());

        Long userId = userCache.getUserId(token);

        Map<String, Object> result = new HashMap<>(2);
        List<CommentIndex> commentIndices = new ArrayList<>();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("contentId", contentId);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(termQueryBuilder);
        //从0页开始查，每页1000个结果
        nativeSearchQueryBuilder.withPageable(PageRequest.of(0, 1000));
        nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("praiseNum").order(SortOrder.DESC));
        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
        ScrolledPage<CommentIndex> pageInfo = (ScrolledPage<CommentIndex>) elasticsearchTemplate.startScroll(1000, nativeSearchQuery, CommentIndex.class);
        do {
            commentIndices.addAll(pageInfo.getContent());
            pageInfo = (ScrolledPage<CommentIndex>) elasticsearchTemplate.continueScroll(pageInfo.getScrollId(), 1000, CommentIndex.class);
        } while (pageInfo.hasContent());

        //及时释放es服务器资源
        elasticsearchTemplate.clearScroll(pageInfo.getScrollId());

        // root 集合
        List<JSONObject> root = commentIndices.parallelStream()
                .filter(commentIndex -> new Long("0").equals(commentIndex.getParentCommentId()))
                .map(commentIndex -> packageComment(commentIndex, userId)).collect(Collectors.toList());

        // 回复 集合
        List<JSONObject> child = commentIndices.parallelStream()
                .filter(commentIndex -> !new Long("0").equals(commentIndex.getParentCommentId()))
                .map(commentIndex -> {
                    JSONObject obj = JSONObject.parseObject(JSON.toJSONString(commentIndex));
                    obj.put("self", false);

                    // 判断是否自己添加的评论
                    if (commentIndex.getUserId().equals(userId)) {
                        obj.put("self", true);
                    }
                    return obj;
                }).collect(Collectors.toList());

        List<JSONObject> indices = root.parallelStream().peek(r -> {
            List<JSONObject> children = child
                    .parallelStream()
                    .filter(c -> c.getLong("parentCommentId").equals(r.getLong("id")))
                    .peek(c -> {
                        c.put("self", false);
                        String existUserIdKey = "userId";
                        // 判断是否自己添加的评论
                        if (c.getLong(existUserIdKey).equals(userId)) {
                            c.put("self", true);
                        }
                    }).collect(Collectors.toList());
            r.put("children", children);
        }).collect(Collectors.toList());

        result.put("total", commentIndices.size());
        result.put("rootTotal", root.size());
        result.put("result", PageUtil.startPage(indices, pageNum, pageSize));
        return result;
    }

    @Override
    public JSONObject findCommentDetail(Map<String, Object> map) {

        String token = map.get("token").toString();
        Long commentId = Long.parseLong(map.get("commentId").toString());

        Long userId = userCache.getUserId(token);

        CommentIndex commentIndex = commentIndexMapper.findById(commentId).get();

        return packageComment(commentIndex, userId);
    }

    @Override
    public Map<String, Object> findCommentDetailChildren(Map<String, Object> map) {

        Map<String, Object> result = new HashMap<>(2);
        String token = map.get("token").toString();
        Long commentId = Long.parseLong(map.get("commentId").toString());
        int pageNum = Integer.parseInt(map.get("pageNum").toString());
        int pageSize = Integer.parseInt(map.get("pageSize").toString());

        Long userId = userCache.getUserId(token);

        CommentIndex commentIndex = new CommentIndex();
        commentIndex.setParentCommentId(commentId);

        Page<CommentIndex> pageInfo = commentIndexMapper.search(SearchUtil.buildBasicQuery(commentIndex, pageNum, pageSize).build());

        List<JSONObject> list = pageInfo.getContent().parallelStream().map(c -> {
            JSONObject obj = JSONObject.parseObject(JSON.toJSONString(c));
            obj.put("self", false);

            // 判断是否自己添加的评论
            if (c.getUserId().equals(userId)) {
                obj.put("self", true);
            }
            return obj;
        }).collect(Collectors.toList());

        result.put("total", pageInfo.getTotalElements());
        result.put("result", list);
        return result;
    }

    private JSONObject packageComment(CommentIndex commentIndex, Long userId) {

        // 评论点赞集合
        Set<Object> objects = redisUtil.sGet(CacheCode.COMMENT_LIKE.getValue());

        JSONObject obj = JSONObject.parseObject(JSON.toJSONString(commentIndex));
        obj.put("self", false);
        obj.put("liked", false);

        // 判断是否自己添加的评论
        if (commentIndex.getUserId().equals(userId)) {
            obj.put("self", true);
        }

        // 判断点赞
        if (!ObjectUtils.isEmpty(objects)) {
            for (Object o : objects) {
                JSONObject json = JsonUtil.jsonToBean(o, JSONObject.class);
                if (userId.equals(json.getLong("userId")) && commentIndex.getId().equals(json.getLong("commentId"))) {
                    obj.put("liked", true);
                }
            }
        }

        return obj;
    }
}
